import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { CreateMemoryDto, UpdateMemoryDto, MemoryQueryDto } from './dto/memory.dto';
import { MemoryType } from '@prisma/client';

@Injectable()
export class MemoryService {
  constructor(private prisma: PrismaService) {}

  // Create memory
  async createMemory(userId: string, createMemoryDto: CreateMemoryDto) {
    const { content, type, importance, tags } = createMemoryDto;
    
    return this.prisma.memory.create({
      data: {
        userId,
        content,
        type: type || MemoryType.FACT,
        importance: importance || 1,
        tags: tags || [],
        sessionId: null,
      },
      select: {
        id: true,
        content: true,
        type: true,
        importance: true,
        tags: true,
        createdAt: true,
        updatedAt: true,
      },
    });
  }

  // Get memory list
  async getMemories(userId: string, query: MemoryQueryDto) {
    const { type, tags, limit = 50, offset = 0 } = query;
    
    const where: any = { 
      userId,
      sessionId: null,
    };
    
    if (type) where.type = type;
    if (tags && tags.length > 0) {
      where.tags = { hasSome: tags };
    }

    const [memories, total] = await Promise.all([
      this.prisma.memory.findMany({
        where,
        orderBy: [
          { importance: 'desc' },
          { createdAt: 'desc' },
        ],
        take: limit,
        skip: offset,
        select: {
          id: true,
          content: true,
          type: true,
          importance: true,
          tags: true,
          createdAt: true,
          updatedAt: true,
          session: {
            select: {
              id: true,
              title: true,
              personaSnapshot: true,
            },
          },
        },
      }),
      this.prisma.memory.count({ where }),
    ]);

    return {
      memories,
      total,
      hasMore: offset + limit < total,
    };
  }

  // Update memory
  async updateMemory(userId: string, memoryId: string, updateMemoryDto: UpdateMemoryDto) {
    const memory = await this.prisma.memory.findFirst({
      where: { id: memoryId, userId },
    });

    if (!memory) {
      throw new NotFoundException('Memory not found');
    }

    return this.prisma.memory.update({
      where: { id: memoryId },
      data: updateMemoryDto,
      select: {
        id: true,
        content: true,
        type: true,
        importance: true,
        tags: true,
        createdAt: true,
        updatedAt: true,
      },
    });
  }

  // Delete memory
  async deleteMemory(userId: string, memoryId: string) {
    const memory = await this.prisma.memory.findFirst({
      where: { id: memoryId, userId },
    });

    if (!memory) {
      throw new NotFoundException('Memory not found');
    }

    await this.prisma.memory.delete({
      where: { id: memoryId },
    });

    return { success: true };
  }

  // Search memories
  async searchMemories(userId: string, query: string, limit = 20) {
    return this.prisma.memory.findMany({
      where: {
        userId,
        content: {
          contains: query,
          mode: 'insensitive',
        },
      },
      orderBy: [
        { importance: 'desc' },
        { createdAt: 'desc' },
      ],
      take: limit,
      select: {
        id: true,
        content: true,
        type: true,
        importance: true,
        tags: true,
        createdAt: true,
        session: {
          select: {
            id: true,
            title: true,
          },
        },
      },
    });
  }

  // Get memory statistics
  async getMemoryStats(userId: string) {
    const [total, byType, recentCount] = await Promise.all([
      this.prisma.memory.count({ where: { userId } }),
      this.prisma.memory.groupBy({
        by: ['type'],
        where: { userId },
        _count: { type: true },
      }),
      this.prisma.memory.count({
        where: {
          userId,
          createdAt: {
            gte: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), // Last 7 days
          },
        },
      }),
    ]);

    return {
      total,
      byType: byType.reduce((acc, item) => {
        acc[item.type] = item._count.type;
        return acc;
      }, {} as Record<string, number>),
      recentCount,
    };
  }
}
